{ "cells": [ { "cell_type": "markdown", "id": "c50e03d7", "metadata": {}, "source": [ "\n", "\n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " Try in Google Colab\n", " \n", " \n", " \n", " \n", " Share via nbviewer\n", " \n", " \n", " \n", " \n", " View on GitHub\n", " \n", " \n", " \n", " \n", " Download notebook\n", " \n", "
\n" ] }, { "cell_type": "markdown", "id": "888e461d", "metadata": {}, "source": [ "# **FiftyOne Group Datasets**\n" ] }, { "cell_type": "markdown", "id": "7530b96a", "metadata": {}, "source": [ "## Creating your First Grouped Dataset" ] }, { "cell_type": "code", "execution_count": 1, "id": "1932bc35", "metadata": {}, "outputs": [], "source": [ "import fiftyone as fo\n", "import fiftyone.utils.random as four\n", "import fiftyone.zoo as foz\n", "\n", "dataset = fo.Dataset(\"first-group-dataset\")\n", "dataset.add_group_field(\"group\", default=\"center\")" ] }, { "cell_type": "markdown", "id": "f6ddeb2c", "metadata": {}, "source": [ "### Adding Images to the dataset" ] }, { "cell_type": "code", "execution_count": 2, "id": "a147f681", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Dataset already downloaded\n", "Loading 'quickstart'\n", " 100% |█████████████████| 200/200 [2.5s elapsed, 0s remaining, 77.1 samples/s] \n", "Dataset 'quickstart' created\n", " 100% |█████████████████| 198/198 [52.7ms elapsed, 0s remaining, 3.8K samples/s] \n" ] }, { "data": { "text/plain": [ "['64f0ff20cb1bdc1e2ee070e2',\n", " '64f0ff20cb1bdc1e2ee070e3',\n", " '64f0ff20cb1bdc1e2ee070e4',\n", " '64f0ff20cb1bdc1e2ee070e5',\n", " '64f0ff20cb1bdc1e2ee070e6',\n", " '64f0ff20cb1bdc1e2ee070e7',\n", " '64f0ff20cb1bdc1e2ee070e8',\n", " '64f0ff20cb1bdc1e2ee070e9',\n", " '64f0ff20cb1bdc1e2ee070ea',\n", " '64f0ff20cb1bdc1e2ee070eb',\n", " '64f0ff20cb1bdc1e2ee070ec',\n", " '64f0ff20cb1bdc1e2ee070ed',\n", " '64f0ff20cb1bdc1e2ee070ee',\n", " '64f0ff20cb1bdc1e2ee070ef',\n", " '64f0ff20cb1bdc1e2ee070f0',\n", " '64f0ff20cb1bdc1e2ee070f1',\n", " '64f0ff20cb1bdc1e2ee070f2',\n", " '64f0ff20cb1bdc1e2ee070f3',\n", " '64f0ff20cb1bdc1e2ee070f4',\n", " '64f0ff20cb1bdc1e2ee070f5',\n", " '64f0ff20cb1bdc1e2ee070f6',\n", " '64f0ff20cb1bdc1e2ee070f7',\n", " '64f0ff20cb1bdc1e2ee070f8',\n", " '64f0ff20cb1bdc1e2ee070f9',\n", " '64f0ff20cb1bdc1e2ee070fa',\n", " '64f0ff20cb1bdc1e2ee070fb',\n", " '64f0ff20cb1bdc1e2ee070fc',\n", " '64f0ff20cb1bdc1e2ee070fd',\n", " '64f0ff20cb1bdc1e2ee070fe',\n", " '64f0ff20cb1bdc1e2ee070ff',\n", " '64f0ff20cb1bdc1e2ee07100',\n", " '64f0ff20cb1bdc1e2ee07101',\n", " '64f0ff20cb1bdc1e2ee07102',\n", " '64f0ff20cb1bdc1e2ee07103',\n", " '64f0ff20cb1bdc1e2ee07104',\n", " '64f0ff20cb1bdc1e2ee07105',\n", " '64f0ff20cb1bdc1e2ee07106',\n", " '64f0ff20cb1bdc1e2ee07107',\n", " '64f0ff20cb1bdc1e2ee07108',\n", " '64f0ff20cb1bdc1e2ee07109',\n", " '64f0ff20cb1bdc1e2ee0710a',\n", " '64f0ff20cb1bdc1e2ee0710b',\n", " '64f0ff20cb1bdc1e2ee0710c',\n", " '64f0ff20cb1bdc1e2ee0710d',\n", " '64f0ff20cb1bdc1e2ee0710e',\n", " '64f0ff20cb1bdc1e2ee0710f',\n", " '64f0ff20cb1bdc1e2ee07110',\n", " '64f0ff20cb1bdc1e2ee07111',\n", " '64f0ff20cb1bdc1e2ee07112',\n", " '64f0ff20cb1bdc1e2ee07113',\n", " '64f0ff20cb1bdc1e2ee07114',\n", " '64f0ff20cb1bdc1e2ee07115',\n", " '64f0ff20cb1bdc1e2ee07116',\n", " '64f0ff20cb1bdc1e2ee07117',\n", " '64f0ff20cb1bdc1e2ee07118',\n", " '64f0ff20cb1bdc1e2ee07119',\n", " '64f0ff20cb1bdc1e2ee0711a',\n", " '64f0ff20cb1bdc1e2ee0711b',\n", " '64f0ff20cb1bdc1e2ee0711c',\n", " '64f0ff20cb1bdc1e2ee0711d',\n", " '64f0ff20cb1bdc1e2ee0711e',\n", " '64f0ff20cb1bdc1e2ee0711f',\n", " '64f0ff20cb1bdc1e2ee07120',\n", " '64f0ff20cb1bdc1e2ee07121',\n", " '64f0ff20cb1bdc1e2ee07122',\n", " '64f0ff20cb1bdc1e2ee07123',\n", " '64f0ff20cb1bdc1e2ee07124',\n", " '64f0ff20cb1bdc1e2ee07125',\n", " '64f0ff20cb1bdc1e2ee07126',\n", " '64f0ff20cb1bdc1e2ee07127',\n", " '64f0ff20cb1bdc1e2ee07128',\n", " '64f0ff20cb1bdc1e2ee07129',\n", " '64f0ff20cb1bdc1e2ee0712a',\n", " '64f0ff20cb1bdc1e2ee0712b',\n", " '64f0ff20cb1bdc1e2ee0712c',\n", " '64f0ff20cb1bdc1e2ee0712d',\n", " '64f0ff20cb1bdc1e2ee0712e',\n", " '64f0ff20cb1bdc1e2ee0712f',\n", " '64f0ff20cb1bdc1e2ee07130',\n", " '64f0ff20cb1bdc1e2ee07131',\n", " '64f0ff20cb1bdc1e2ee07132',\n", " '64f0ff20cb1bdc1e2ee07133',\n", " '64f0ff20cb1bdc1e2ee07134',\n", " '64f0ff20cb1bdc1e2ee07135',\n", " '64f0ff20cb1bdc1e2ee07136',\n", " '64f0ff20cb1bdc1e2ee07137',\n", " '64f0ff20cb1bdc1e2ee07138',\n", " '64f0ff20cb1bdc1e2ee07139',\n", " '64f0ff20cb1bdc1e2ee0713a',\n", " '64f0ff20cb1bdc1e2ee0713b',\n", " '64f0ff20cb1bdc1e2ee0713c',\n", " '64f0ff20cb1bdc1e2ee0713d',\n", " '64f0ff20cb1bdc1e2ee0713e',\n", " '64f0ff20cb1bdc1e2ee0713f',\n", " '64f0ff20cb1bdc1e2ee07140',\n", " '64f0ff20cb1bdc1e2ee07141',\n", " '64f0ff20cb1bdc1e2ee07142',\n", " '64f0ff20cb1bdc1e2ee07143',\n", " '64f0ff20cb1bdc1e2ee07144',\n", " '64f0ff20cb1bdc1e2ee07145',\n", " '64f0ff20cb1bdc1e2ee07146',\n", " '64f0ff20cb1bdc1e2ee07147',\n", " '64f0ff20cb1bdc1e2ee07148',\n", " '64f0ff20cb1bdc1e2ee07149',\n", " '64f0ff20cb1bdc1e2ee0714a',\n", " '64f0ff20cb1bdc1e2ee0714b',\n", " '64f0ff20cb1bdc1e2ee0714c',\n", " '64f0ff20cb1bdc1e2ee0714d',\n", " '64f0ff20cb1bdc1e2ee0714e',\n", " '64f0ff20cb1bdc1e2ee0714f',\n", " '64f0ff20cb1bdc1e2ee07150',\n", " '64f0ff20cb1bdc1e2ee07151',\n", " '64f0ff20cb1bdc1e2ee07152',\n", " '64f0ff20cb1bdc1e2ee07153',\n", " '64f0ff20cb1bdc1e2ee07154',\n", " '64f0ff20cb1bdc1e2ee07155',\n", " '64f0ff20cb1bdc1e2ee07156',\n", " '64f0ff20cb1bdc1e2ee07157',\n", " '64f0ff20cb1bdc1e2ee07158',\n", " '64f0ff20cb1bdc1e2ee07159',\n", " '64f0ff20cb1bdc1e2ee0715a',\n", " '64f0ff20cb1bdc1e2ee0715b',\n", " '64f0ff20cb1bdc1e2ee0715c',\n", " '64f0ff20cb1bdc1e2ee0715d',\n", " '64f0ff20cb1bdc1e2ee0715e',\n", " '64f0ff20cb1bdc1e2ee0715f',\n", " '64f0ff20cb1bdc1e2ee07160',\n", " '64f0ff20cb1bdc1e2ee07161',\n", " '64f0ff20cb1bdc1e2ee07162',\n", " '64f0ff20cb1bdc1e2ee07163',\n", " '64f0ff20cb1bdc1e2ee07164',\n", " '64f0ff20cb1bdc1e2ee07165',\n", " '64f0ff20cb1bdc1e2ee07166',\n", " '64f0ff20cb1bdc1e2ee07167',\n", " '64f0ff20cb1bdc1e2ee07168',\n", " '64f0ff20cb1bdc1e2ee07169',\n", " '64f0ff20cb1bdc1e2ee0716a',\n", " '64f0ff20cb1bdc1e2ee0716b',\n", " '64f0ff20cb1bdc1e2ee0716c',\n", " '64f0ff20cb1bdc1e2ee0716d',\n", " '64f0ff20cb1bdc1e2ee0716e',\n", " '64f0ff20cb1bdc1e2ee0716f',\n", " '64f0ff20cb1bdc1e2ee07170',\n", " '64f0ff20cb1bdc1e2ee07171',\n", " '64f0ff20cb1bdc1e2ee07172',\n", " '64f0ff20cb1bdc1e2ee07173',\n", " '64f0ff20cb1bdc1e2ee07174',\n", " '64f0ff20cb1bdc1e2ee07175',\n", " '64f0ff20cb1bdc1e2ee07176',\n", " '64f0ff20cb1bdc1e2ee07177',\n", " '64f0ff20cb1bdc1e2ee07178',\n", " '64f0ff20cb1bdc1e2ee07179',\n", " '64f0ff20cb1bdc1e2ee0717a',\n", " '64f0ff20cb1bdc1e2ee0717b',\n", " '64f0ff20cb1bdc1e2ee0717c',\n", " '64f0ff20cb1bdc1e2ee0717d',\n", " '64f0ff20cb1bdc1e2ee0717e',\n", " '64f0ff20cb1bdc1e2ee0717f',\n", " '64f0ff20cb1bdc1e2ee07180',\n", " '64f0ff20cb1bdc1e2ee07181',\n", " '64f0ff20cb1bdc1e2ee07182',\n", " '64f0ff20cb1bdc1e2ee07183',\n", " '64f0ff20cb1bdc1e2ee07184',\n", " '64f0ff20cb1bdc1e2ee07185',\n", " '64f0ff20cb1bdc1e2ee07186',\n", " '64f0ff20cb1bdc1e2ee07187',\n", " '64f0ff20cb1bdc1e2ee07188',\n", " '64f0ff20cb1bdc1e2ee07189',\n", " '64f0ff20cb1bdc1e2ee0718a',\n", " '64f0ff20cb1bdc1e2ee0718b',\n", " '64f0ff20cb1bdc1e2ee0718c',\n", " '64f0ff20cb1bdc1e2ee0718d',\n", " '64f0ff20cb1bdc1e2ee0718e',\n", " '64f0ff20cb1bdc1e2ee0718f',\n", " '64f0ff20cb1bdc1e2ee07190',\n", " '64f0ff20cb1bdc1e2ee07191',\n", " '64f0ff20cb1bdc1e2ee07192',\n", " '64f0ff20cb1bdc1e2ee07193',\n", " '64f0ff20cb1bdc1e2ee07194',\n", " '64f0ff20cb1bdc1e2ee07195',\n", " '64f0ff20cb1bdc1e2ee07196',\n", " '64f0ff20cb1bdc1e2ee07197',\n", " '64f0ff20cb1bdc1e2ee07198',\n", " '64f0ff20cb1bdc1e2ee07199',\n", " '64f0ff20cb1bdc1e2ee0719a',\n", " '64f0ff20cb1bdc1e2ee0719b',\n", " '64f0ff20cb1bdc1e2ee0719c',\n", " '64f0ff20cb1bdc1e2ee0719d',\n", " '64f0ff20cb1bdc1e2ee0719e',\n", " '64f0ff20cb1bdc1e2ee0719f',\n", " '64f0ff20cb1bdc1e2ee071a0',\n", " '64f0ff20cb1bdc1e2ee071a1',\n", " '64f0ff20cb1bdc1e2ee071a2',\n", " '64f0ff20cb1bdc1e2ee071a3',\n", " '64f0ff20cb1bdc1e2ee071a4',\n", " '64f0ff20cb1bdc1e2ee071a5',\n", " '64f0ff20cb1bdc1e2ee071a6',\n", " '64f0ff20cb1bdc1e2ee071a7']" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "groups = [\"left\", \"center\", \"right\"]\n", "\n", "d = foz.load_zoo_dataset(\"quickstart\")\n", "four.random_split(d, {g: 1 / len(groups) for g in groups})\n", "filepaths = [d.match_tags(g).values(\"filepath\") for g in groups]\n", "filepaths = [dict(zip(groups, fps)) for fps in zip(*filepaths)]\n", "\n", "samples = []\n", "for fps in filepaths:\n", " group = fo.Group()\n", " for name, filepath in fps.items():\n", " sample = fo.Sample(filepath=filepath, group=group.element(name))\n", " samples.append(sample)\n", "\n", "dataset.add_samples(samples)" ] }, { "cell_type": "code", "execution_count": 3, "id": "00e7e60f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Name: first-group-dataset\n", "Media type: group\n", "Group slice: center\n", "Num groups: 66\n", "Persistent: False\n", "Tags: []\n", "Sample fields:\n", " id: fiftyone.core.fields.ObjectIdField\n", " filepath: fiftyone.core.fields.StringField\n", " tags: fiftyone.core.fields.ListField(fiftyone.core.fields.StringField)\n", " metadata: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.metadata.Metadata)\n", " group: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.groups.Group)\n" ] } ], "source": [ "print(dataset)" ] }, { "cell_type": "code", "execution_count": 4, "id": "be25db11", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "
\n", "
\n", " \n", "
\n", " \n", "
\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "session = fo.launch_app(dataset)" ] }, { "cell_type": "markdown", "id": "6ba3b784", "metadata": {}, "source": [ "### Grabbing basic information" ] }, { "cell_type": "code", "execution_count": 5, "id": "b1f1eb7f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['left', 'center', 'right']\n" ] } ], "source": [ "print(dataset.group_slices)" ] }, { "cell_type": "code", "execution_count": 6, "id": "67b3bac5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'left': 'image', 'center': 'image', 'right': 'image'}\n" ] } ], "source": [ "print(dataset.group_media_types)" ] }, { "cell_type": "markdown", "id": "5becbd6d", "metadata": {}, "source": [ "### Grabbing a single sample" ] }, { "cell_type": "code", "execution_count": 7, "id": "100cb1ac", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ",\n", "}>\n" ] } ], "source": [ "sample = dataset.shuffle().first()\n", "print(sample)" ] }, { "cell_type": "markdown", "id": "e8d0f6e4", "metadata": {}, "source": [ " ### In a grouped dataset, you have one active group slice at a time. A group slice makes up each inidividual sample of each group in that slice. Another way to put it is that in the left group slice, we will see all the left photos. We can change this easily by following below:" ] }, { "cell_type": "code", "execution_count": 8, "id": "fa60eed2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ",\n", "}>\n" ] } ], "source": [ "dataset.group_slice = \"left\"\n", "sample = dataset.shuffle().first()\n", "print(sample)" ] }, { "cell_type": "code", "execution_count": 9, "id": "a22091a6", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "
\n", "
\n", " \n", "
\n", " \n", "
\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "session = fo.launch_app(dataset)" ] }, { "cell_type": "code", "execution_count": 10, "id": "77ab7bd8", "metadata": {}, "outputs": [], "source": [ "dataset.group_slice = \"center\"" ] }, { "cell_type": "code", "execution_count": 11, "id": "9c4d2542", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'left': ,\n", "}>, 'center': ,\n", "}>, 'right': ,\n", "}>}\n" ] } ], "source": [ "sample = dataset.shuffle().first()\n", "group_id = sample.group.id\n", "\n", "group = dataset.get_group(group_id)\n", "print(group)" ] }, { "cell_type": "code", "execution_count": 12, "id": "2331ee54", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Dataset already downloaded\n", "Loading 'quickstart-groups'\n", " 100% |█████████████████| 600/600 [2.0s elapsed, 0s remaining, 308.7 samples/s] \n", "Dataset 'quickstart-groups' created\n", "left\n" ] }, { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import fiftyone as fo\n", "import fiftyone.zoo as foz\n", "from fiftyone import ViewField as F\n", "\n", "dataset = foz.load_zoo_dataset(\"quickstart-groups\")\n", "\n", "print(dataset.group_slice)\n", "# left\n", "\n", "session = fo.launch_app(dataset)" ] }, { "cell_type": "code", "execution_count": 13, "id": "8d74c905", "metadata": {}, "outputs": [], "source": [ "# Filters based on the content in the 'left' slice\n", "view = (\n", " dataset\n", " .match_tags(\"train\")\n", " .filter_labels(\"ground_truth\", F(\"label\") == \"Pedestrian\")\n", ")" ] }, { "cell_type": "code", "execution_count": 14, "id": "11a3d6e7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Dataset: quickstart-groups\n", "Media type: group\n", "Group slice: left\n", "Num groups: 0\n", "Group fields:\n", " id: fiftyone.core.fields.ObjectIdField\n", " filepath: fiftyone.core.fields.StringField\n", " tags: fiftyone.core.fields.ListField(fiftyone.core.fields.StringField)\n", " metadata: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.metadata.Metadata)\n", " group: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.groups.Group)\n", " ground_truth: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.labels.Detections)\n", "View stages:\n", " 1. Match(filter={'$expr': {'$and': [...]}})\n" ] } ], "source": [ "from fiftyone import ViewField as F\n", "\n", "dataset.compute_metadata()\n", "\n", "# Match groups whose `left` image has a height of at least 640 pixels and\n", "# whose `right` image has a height of at most 480 pixels\n", "view = dataset.match(\n", " (F(\"groups.left.metadata.height\") >= 640)\n", " & (F(\"groups.right.metadata.height\") <= 480)\n", ")\n", "\n", "print(view)\n" ] }, { "cell_type": "code", "execution_count": 15, "id": "fd995df1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "left\n", "1379\n", "9291.526529006525\n" ] } ], "source": [ "bbox_width = F(\"bounding_box\")[2] * F(\"$metadata.width\")\n", "bbox_height = F(\"bounding_box\")[3] * F(\"$metadata.height\")\n", "bbox_area = bbox_width * bbox_height\n", "\n", "print(dataset.group_slice)\n", "# left\n", "\n", "print(dataset.count(\"ground_truth.detections\"))\n", "\n", "print(dataset.mean(\"ground_truth.detections[]\", expr=bbox_area))" ] }, { "cell_type": "code", "execution_count": 16, "id": "8de987a4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1100\n", "(221.24430441846425, 466616.0)\n" ] } ], "source": [ "dataset.group_slice = \"right\"\n", "\n", "print(dataset.count(\"ground_truth.detections\"))\n", "\n", "print(dataset.bounds(\"ground_truth.detections[]\", expr=bbox_area))" ] }, { "cell_type": "code", "execution_count": 17, "id": "896544f9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "200\n", "1100\n", "400\n", "2479\n" ] } ], "source": [ "print(dataset.count()) # 200\n", "print(dataset.count(\"ground_truth.detections\")) # 1438\n", "\n", "view3 = dataset.select_group_slices([\"left\", \"right\"])\n", "\n", "print(view3.count()) # 400\n", "print(view3.count(\"ground_truth.detections\")) # 2876" ] }, { "cell_type": "code", "execution_count": 18, "id": "9094d15e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Dataset: quickstart-groups\n", "Media type: group\n", "Group slice: right\n", "Num groups: 86\n", "Group fields:\n", " id: fiftyone.core.fields.ObjectIdField\n", " filepath: fiftyone.core.fields.StringField\n", " tags: fiftyone.core.fields.ListField(fiftyone.core.fields.StringField)\n", " metadata: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.metadata.Metadata)\n", " group: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.groups.Group)\n", " ground_truth: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.labels.Detections)\n", "View stages:\n", " 1. FilterLabels(field='ground_truth', filter={'$and': [{...}, {...}]}, only_matches=True, trajectories=False)\n" ] } ], "source": [ "bbox_width = F(\"bounding_box\")[2] \n", "bbox_height = F(\"bounding_box\")[3] \n", "bbox_area = bbox_width * bbox_height\n", "\n", "view = dataset.filter_labels(\"ground_truth\", (0.05 <= bbox_area) & (bbox_area < 0.5))\n", "print(view)" ] }, { "cell_type": "code", "execution_count": null, "id": "a689a1ed", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13" } }, "nbformat": 4, "nbformat_minor": 5 }